package com.zhiche.wms.service.inbound.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.zhiche.wms.core.supports.BaseException;
import com.zhiche.wms.core.supports.enums.TableStatusEnum;
import com.zhiche.wms.core.utils.SnowFlakeId;
import com.zhiche.wms.domain.mapper.inbound.FactoryPrepareInboundMapper;
import com.zhiche.wms.domain.mapper.inbound.InboundNoticeLineMapper;
import com.zhiche.wms.domain.mapper.otm.OtmOrderReleaseMapper;
import com.zhiche.wms.domain.mapper.stock.StockDetailMapper;
import com.zhiche.wms.domain.mapper.stock.StockMapper;
import com.zhiche.wms.domain.model.base.StoreLocation;
import com.zhiche.wms.domain.model.base.Storehouse;
import com.zhiche.wms.domain.model.inbound.FactoryPrepareInbound;
import com.zhiche.wms.domain.model.inbound.InboundNoticeLine;
import com.zhiche.wms.domain.model.otm.OtmOrderRelease;
import com.zhiche.wms.domain.model.stock.Sku;
import com.zhiche.wms.domain.model.stock.Stock;
import com.zhiche.wms.domain.model.stock.StockDetail;
import com.zhiche.wms.domain.model.sys.User;
import com.zhiche.wms.dto.inbound.FPInboundDTO;
import com.zhiche.wms.dto.outbound.FPOutboundDTO;
import com.zhiche.wms.dto.outbound.FactoryShipmentOutDTO;
import com.zhiche.wms.service.base.IStoreLocationService;
import com.zhiche.wms.service.base.IStorehouseService;
import com.zhiche.wms.service.dto.FactoryPrepareInboundVo;
import com.zhiche.wms.service.inbound.IFactoryPreInboundService;
import com.zhiche.wms.service.stock.ISkuService;
import com.zhiche.wms.service.stock.IStockService;
import com.zhiche.wms.service.sys.IUserService;
import com.zhiche.wms.service.utils.CommonFields;
import com.zhiche.wms.service.utils.CommonMethod;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;

/**
 * @Author: caiHua
 * @Description: 工厂备料入库
 * @Date: Create in 11:09 2019/11/20
 */
@Service
public class FactoryPrepareServiceImpl extends ServiceImpl<FactoryPrepareInboundMapper, FactoryPrepareInbound> implements IFactoryPreInboundService {

    private static final Logger LOGGER = LoggerFactory.getLogger(FactoryPrepareServiceImpl.class);

    @Autowired
    private IUserService userService;
    @Autowired
    private InboundNoticeLineMapper inboundNoticeLineMapper;
    @Autowired
    private IStoreLocationService storeLocationService;
    @Autowired
    private ISkuService iSkuService;
    @Autowired
    private SnowFlakeId snowFlakeId;
    @Autowired
    private IStockService iStockService;
    @Autowired
    private StockDetailMapper stockDetailMapper;
    @Autowired
    private StockMapper stockMapper;
    @Autowired
    private IStorehouseService iStorehouseService;
    @Autowired
    private OtmOrderReleaseMapper otmOrderReleaseMapper;

    @Override
    public List<String> prepareInbound (FactoryPrepareInboundVo fpiVo) {
        checkParam(fpiVo);
        User loginUser = userService.getLoginUser();
        if (loginUser == null) {
            throw new BaseException("未查询到登录用户");
        }

        //获取可无单备料入库的仓库
        EntityWrapper<Storehouse> storehouseEntityWrapper = new EntityWrapper<>();
        storehouseEntityWrapper.ne("property", TableStatusEnum.STATUS_10.getCode());
        List<Storehouse> storeHouses = iStorehouseService.selectList(storehouseEntityWrapper);
        List<Long> storeHouseIds = null;
        if (CollectionUtils.isEmpty(storeHouses) || storeHouses.size() < 1) {
            throw new BaseException("未找到可无单备料仓库");
        } else {
            storeHouseIds = new ArrayList<>();
            for (Storehouse storehouse : storeHouses) {
                storeHouseIds.add(storehouse.getId());
            }
        }

        List<String> resultList = new ArrayList<>();
        FactoryPrepareInbound factoryPrepareInbound = new FactoryPrepareInbound();
        factoryPrepareInbound.setAreaId(fpiVo.getAreaId());
        factoryPrepareInbound.setInboundUser(loginUser.getName());
        factoryPrepareInbound.setStoreHouseId(fpiVo.getStoreHouseId());
        factoryPrepareInbound.setPrepareStatus(TableStatusEnum.STATUS_10.getCode());
        List<String> vins = Arrays.asList(CommonMethod.setVins(fpiVo.getVins()));
        for (String vin : vins) {
            StringBuffer sb = new StringBuffer();
            try {
                if (!storeHouseIds.contains(fpiVo.getStoreHouseId())) {
                    sb.append("车架号:").append(vin).append(":").append("当前仓库不允许导入!");
                    resultList.add(sb.toString());
                    continue;
                }
                StoreLocation storeLocation = storeLocationService.queryUsableLocationByAreaId(fpiVo.getStoreHouseId(), fpiVo.getAreaId());
                if (Objects.isNull(storeLocation)) {
                    sb.append("车架号:").append(vin).append(":").append("当前库区" + fpiVo.getAreaId() + "无可用库位");
                    resultList.add(sb.toString());
                    continue;
                }
                EntityWrapper<InboundNoticeLine> inboundEw = new EntityWrapper<>();
                inboundEw.eq(CommonFields.LOT_NO1.getCode(), vin);
                List<InboundNoticeLine> inboundList = inboundNoticeLineMapper.selectList(inboundEw);
                if (CollectionUtils.isNotEmpty(inboundList)) {
                    sb.append("车架号:").append(vin).append(":").append("已经下发过提车入库指令至wms，请勿重复添加");
                    resultList.add(sb.toString());
                    continue;
                }
                //是否已经有入库备料数据
                EntityWrapper<FactoryPrepareInbound> factoryEw = new EntityWrapper<>();
                factoryEw.eq(CommonFields.VIN.getCode(), vin);
                factoryEw.ne(CommonFields.PREPARE_STATUS.getCode(), TableStatusEnum.STATUS_40.getCode());
                List<FactoryPrepareInbound> factoryPrepareInbounds = baseMapper.selectList(factoryEw);
                if (CollectionUtils.isNotEmpty(factoryPrepareInbounds)) {
                    sb.append("车架号:").append(vin).append(":").append("已经添加过无单备料数据，请勿重复添加");
                    resultList.add(sb.toString());
                    continue;
                }
                factoryPrepareInbound.setVin(vin);
                factoryPrepareInbound.setGmtCreated(new Date());
                factoryPrepareInbound.setInboundTime(new Date());
                factoryPrepareInbound.setId(snowFlakeId.nextId());
                factoryPrepareInbound.setLocationId(storeLocation.getId());
                factoryPrepareInbound.setLocationNo(storeLocation.getCode());
                saveStock(storeLocation.getId(), fpiVo.getStoreHouseId(), fpiVo.getAreaId(), vin, factoryPrepareInbound);
                baseMapper.insert(factoryPrepareInbound);
            } catch (BaseException be) {
                sb.append("车架号:").append(vin).append(":").append(be.getMessage());
                resultList.add(sb.toString());
            } catch (Exception e) {
                LOGGER.error("调用prepareInbound方法异常{}", e.getMessage());
                sb.append("车架号:").append(vin).append(":").append("系统异常");
                resultList.add(sb.toString());
            }
        }
        return resultList;
    }

    @Override
    public List<String> outboundPrepare (FactoryPrepareInboundVo param) {
        User loginUser = userService.getLoginUser();
        if (loginUser == null) {
            throw new BaseException("未查询到登录用户");
        }
        checkOutboundParam(param);
        List<String> resultList = new ArrayList<>();

        String[] ids = param.getPrepareInboundId().split(",");
        String[] vins = param.getVins().split(",");
        if (TableStatusEnum.STATUS_20.getCode().equals(param.getHandlerType()) || TableStatusEnum.STATUS_40.getCode().equals(param.getHandlerType())
                || TableStatusEnum.STATUS_60.getCode().equals(param.getHandlerType())) {
            outCleanFactoryStock(ids, loginUser.getName(), param.getHandlerType(), param.getRemarks());
        } else if (TableStatusEnum.STATUS_30.getCode().equals(param.getHandlerType())) {
            //如果有提车段的指令，把提车段的起始地更改为无单库的所在地址
            for (int i = 0; i < ids.length && i < vins.length; i++) {
                StringBuffer sb = new StringBuffer();
                FactoryShipmentOutDTO factoryDTO = baseMapper.queryStoreArea(Long.valueOf(ids[i]));
                if (null != factoryDTO) {
                    OtmOrderRelease updateParam = new OtmOrderRelease();
                    updateParam.setId(factoryDTO.getOorId());
                    String areaName = factoryDTO.getAreaName();
                    if (!areaName.contains("区")) {
                        areaName += "区";
                    }
                    updateParam.setRealVehicleAddress(factoryDTO.getStoreHouseName() + areaName + factoryDTO.getLocationName());
                    otmOrderReleaseMapper.updateById(updateParam);
                    outCleanFactoryStock(ids, loginUser.getName(), param.getHandlerType(), param.getRemarks());
                } else {
                    sb.append("车架号:").append(vins[i]).append(":").append("未下发提车指令，不允许出库");
                    resultList.add(sb.toString());
                    continue;
                }
            }
        } else {
            throw new BaseException("出库类型异常！");
        }
        return resultList;
        /*else if (TableStatusEnum.STATUS_30.getCode().equals(param.getHandlerType())) {
            for (int i = 0; i < ids.length && i < vins.length; i++) {
                StringBuffer sb = new StringBuffer();
                try {
                    EntityWrapper<FactoryOutboundShipmentDTO> outEw = new EntityWrapper<>();
                    outEw.eq("fpi.vin", vins[i]);
                    outEw.eq("fpi.id", ids[i]);
                    List<FactoryOutboundShipmentDTO> tcShipment = inboundNoticeLineMapper.tcShipmentGidOut(outEw);
                    if (CollectionUtils.isNotEmpty(tcShipment)) {
                        FactoryPrepareInbound updateFpi = new FactoryPrepareInbound();
                        updateFpi.setId(tcShipment.get(0).getFpiId());
                        updateFpi.setOutboundTime(new Date());
                        updateFpi.setOutboundUser("库内转换");
                        updateFpi.setShipmentGid(tcShipment.get(0).getShipment_gid());
                        updateFpi.setPrepareStatus(TableStatusEnum.STATUS_30.getCode());
                        if (StringUtils.isNotBlank(param.getRemarks())) {
                            updateFpi.setRemarks(param.getRemarks());
                        }
                        baseMapper.updateById(updateFpi);
                        iStockService.cleanStockData(tcShipment.get(0).getFpiId(), "备转正");
                        iInboundPutawayHeaderService.updateByNoticeLineId(tcShipment.get(0).getNoticeLineId(), PutAwayType.NOTICE_PUTAWAY, SourceSystem.AUTO,
                                tcShipment.get(0).getAreaId());
                        InboundNoticeLine updateInbound = new InboundNoticeLine();
                        updateInbound.setId(tcShipment.get(0).getNoticeLineId());
                        updateInbound.setRemarks("备转正");
                        inboundNoticeLineMapper.updateById(updateInbound);
                    } else {
                        sb.append("车架号:").append(vins[i]).append(":").append("未下发提车指令或者仓库不同，不允许出库");
                        resultList.add(sb.toString());
                        continue;
                    }
                } catch (BaseException be) {
                    sb.append("车架号:").append(vins[i]).append(":").append(be.getMessage());
                    resultList.add(sb.toString());
                } catch (Exception e) {
                    LOGGER.error("调用prepareInbound方法异常{}", e.getMessage());
                    sb.append("车架号:").append(vins[i]).append(":").append("系统异常");
                    resultList.add(sb.toString());
                }
            }
        }*/
    }

    private void outCleanFactoryStock (String[] ids, String loginName, String handlerType,String remarks) {
        EntityWrapper<FactoryPrepareInbound> factoryEw = new EntityWrapper<>();
        factoryEw.in(CommonFields.ID.getCode(), ids);
        factoryEw.eq("prepare_status", TableStatusEnum.STATUS_10.getCode());
        FactoryPrepareInbound factoryPrepareInbound = new FactoryPrepareInbound();
        factoryPrepareInbound.setOutboundTime(new Date());
        factoryPrepareInbound.setOutboundUser(loginName);
        factoryPrepareInbound.setPrepareStatus(handlerType);
        if (StringUtils.isNotBlank(remarks)) {
            factoryPrepareInbound.setRemarks(remarks);
        }
        baseMapper.update(factoryPrepareInbound, factoryEw);
        //清理库存
        EntityWrapper<FactoryPrepareInbound> factoryStockEw = new EntityWrapper<>();
        factoryStockEw.in(CommonFields.ID.getCode(), ids);
        List<FactoryPrepareInbound> stockIds = baseMapper.selectList(factoryStockEw);
        for (FactoryPrepareInbound fpInbound : stockIds) {
            iStockService.cleanStockData(fpInbound.getStockId(), "无单");
        }
    }

    @Override
    public Page<FPOutboundDTO> queryFactoryOutbound (Page<FPOutboundDTO> page) {
        Map<String, Object> condition = page.getCondition();
        EntityWrapper<FPOutboundDTO> factoryEw = new EntityWrapper<>();
        if (null != condition) {
            if (condition.containsKey("startDate") && StringUtils.isNotBlank((String) condition.get("startDate"))) {
                factoryEw.ge("outbound_time", condition.get("startDate"));
            }
            if (condition.containsKey("endDate") && StringUtils.isNotBlank((String) condition.get("endDate"))) {
                factoryEw.le("outbound_time", condition.get("endDate"));
            }
            if (condition.containsKey("storeHouseName") && StringUtils.isNotBlank((String) condition.get("storeHouseName"))) {
                factoryEw.like("storeHouseName", condition.get("storeHouseName").toString());
            }
            if (condition.containsKey("prepareStatus") && StringUtils.isNotBlank((String) condition.get("prepareStatus"))) {
                factoryEw.eq("prepare_status", condition.get("prepareStatus").toString());
            } else {
                List<String> statusList = new ArrayList<>();
                statusList.add(TableStatusEnum.STATUS_10.getCode());
                statusList.add(TableStatusEnum.STATUS_50.getCode());
                factoryEw.notIn("prepare_status", statusList);
            }
            if (condition.containsKey("vin") && StringUtils.isNotBlank((String) condition.get("vin"))) {
                List<String> vins = Arrays.asList(CommonMethod.setVins((String) condition.get("vin")));
                factoryEw.andNew().in(CommonFields.VIN.getCode(), vins).or().like(CommonFields.VIN.getCode(), condition.get("vin").toString());
            }
        }
        factoryEw.orderBy("outbound_time", false);
        List<FPOutboundDTO> factoryPrepareInbounds;
        if (TableStatusEnum.STATUS_Y.getCode().equals(condition.get("queryType"))) {
            factoryPrepareInbounds = baseMapper.queryFactoryOutBound(factoryEw, page);
        } else {
            factoryPrepareInbounds = baseMapper.queryFactoryOutBound(factoryEw);
        }
        return page.setRecords(factoryPrepareInbounds);
    }

    @Override
    public Page<FPInboundDTO> queryFactoryInbound (Page<FPInboundDTO> page) {
        Map<String, Object> condition = page.getCondition();
        EntityWrapper<FPInboundDTO> factoryEw = new EntityWrapper<>();
        factoryEw.ne("prepare_status", TableStatusEnum.STATUS_50.getCode());
        if (null != condition) {
            if (condition.containsKey("startDate") && StringUtils.isNotBlank((String) condition.get("startDate"))) {
                factoryEw.ge("inbound_time", condition.get("startDate"));
            }
            if (condition.containsKey("endDate") && StringUtils.isNotBlank((String) condition.get("endDate"))) {
                factoryEw.le("inbound_time", condition.get("endDate"));
            }
            if (condition.containsKey("storeHouseName") && StringUtils.isNotBlank((String) condition.get("storeHouseName"))) {
                factoryEw.like("storeHouseName", condition.get("storeHouseName").toString());
            }
            if (condition.containsKey("vin") && StringUtils.isNotBlank((String) condition.get("vin"))) {
                List<String> vins = Arrays.asList(CommonMethod.setVins((String) condition.get("vin")));
                factoryEw.andNew().in(CommonFields.VIN.getCode(), vins).or().like(CommonFields.VIN.getCode(), condition.get("vin").toString());
            }
        }
        factoryEw.orderBy("inbound_time", false);
        List<FPInboundDTO> factoryPrepareInbounds;
        if (TableStatusEnum.STATUS_Y.getCode().equals(condition.get("queryType"))) {
            factoryPrepareInbounds = baseMapper.queryFactoryInBound(factoryEw, page);
        } else {
            factoryPrepareInbounds = baseMapper.queryFactoryInBound(factoryEw);
        }

        return page.setRecords(factoryPrepareInbounds);
    }

    @Override
    public Map<String, Object> queryMustMatter (Map<String, String> param) {
        if (null == param || param.isEmpty()) {
            throw new BaseException("入参不能为空");
        }
        String storeHouseId = param.get("storeHouseId");
        if (StringUtils.isBlank(storeHouseId)) {
            throw new BaseException("仓库不能为空");
        }
        Map<String, Object> resultMap = new HashMap<>();
        EntityWrapper<FactoryPrepareInbound> ew = new EntityWrapper<>();
        ew.eq("fpi.store_house_id", storeHouseId);
        ew.eq("fpi.prepare_status", TableStatusEnum.STATUS_10.getCode());
        List<FactoryPrepareInbound> list = baseMapper.queryMustMatter(ew);
        if (CollectionUtils.isNotEmpty(list) && list.size() > 0) {
            resultMap.put("linkType", "10");
            resultMap.put("message", "当前无单库存有[" + list.size() + "]台已收到工厂备料提车指令,请及时处理，详情点击连接！");
        }
        return resultMap;
    }

    private void checkOutboundParam (FactoryPrepareInboundVo param) {
        if (null == param || Objects.isNull(param)) {
            throw new BaseException("出库参数不能为空");
        }
        if (StringUtils.isBlank(param.getPrepareInboundId())) {
            throw new BaseException("请选择需要出库的数据");
        }
        if (StringUtils.isBlank(param.getVins())) {
            throw new BaseException("请选择需要出库的数据");
        }
        //20:移实顺,30：已出库(提车指令出库) ，40：返工厂
        if (StringUtils.isBlank(param.getHandlerType())) {
            throw new BaseException("出库操作类型不能为空！");
        }
    }

    private void saveStock (Long locationId, Long storeHouseId, Long areaId, String vin, FactoryPrepareInbound factoryPrepareInbound) {
        //1、查询SKU是否有数据，无则新增，有则获取id
        Long skuId = querySku(vin);
        factoryPrepareInbound.setSkuId(skuId);

        //2、新增库存
        insertStock(factoryPrepareInbound, skuId, storeHouseId, locationId);

        //3、新增库存明细
        StockDetail stockDetail = new StockDetail();
        stockDetail.setId(snowFlakeId.nextId());
        stockDetail.setStockId(factoryPrepareInbound.getStockId());
        stockDetail.setType(TableStatusEnum.STATUS_10.getCode());
        stockDetail.setBusinessType(TableStatusEnum.STATUS_40.getCode());
        stockDetail.setQty(BigDecimal.ONE);
        stockDetailMapper.insert(stockDetail);
    }

    private void insertStock (FactoryPrepareInbound factoryPrepareInbound, Long skuId, Long storeHouseId, Long locationId) {
        EntityWrapper<Stock> stockEw = new EntityWrapper<>();
        stockEw.eq("sku_id", skuId);
        stockEw.eq("location_id", locationId);
        stockEw.eq(CommonFields.STORE_HOUSE_ID.getCode(), storeHouseId);
        List<Stock> stocks = stockMapper.selectList(stockEw);
        if (CollectionUtils.isNotEmpty(stocks)) {
            factoryPrepareInbound.setStockId(stocks.get(0).getId());
            if (stocks.get(0).getQty().compareTo(BigDecimal.ZERO) == 0) {
                Stock updateStock = new Stock();
                updateStock.setId(stocks.get(0).getId());
                updateStock.setQty(BigDecimal.ONE);
                stockMapper.updateById(updateStock);
            }
        } else {
            Stock stock = new Stock();
            stock.setSkuId(skuId);
            stock.setQty(BigDecimal.ONE);
            stock.setLocationId(locationId);
            stock.setId(snowFlakeId.nextId());
            stock.setNetWeight(BigDecimal.ZERO);
            stock.setStoreHouseId(storeHouseId);
            stock.setGrossWeight(BigDecimal.ZERO);
            stock.setGrossCubage(BigDecimal.ZERO);
            stock.setPackedCount(BigDecimal.ZERO);
            stock.setStockProperty("无单");
            factoryPrepareInbound.setStockId(stock.getId());
            stockMapper.insert(stock);
        }
    }

    private Long querySku (String vin) {
        Sku sku = iSkuService.querySkuInfo(vin);
        if (null != sku) {
            return sku.getId();
        }
        Sku insertSku = new Sku();
        insertSku.setId(snowFlakeId.nextId());
        insertSku.setLotNo1(vin);
        insertSku.setUom("台");
        iSkuService.insert(insertSku);
        return insertSku.getId();
    }

    private void checkParam (FactoryPrepareInboundVo factoryPrepareInboundVo) {
        if (null == factoryPrepareInboundVo) {
            throw new BaseException("入参不能为空");
        }
        if (StringUtils.isEmpty(factoryPrepareInboundVo.getVins())) {
            throw new BaseException("备料车架号不能为空");
        }
        if (null == factoryPrepareInboundVo.getStoreHouseId()) {
            throw new BaseException("入库仓库不能为空");
        }
        if (null == factoryPrepareInboundVo.getAreaId()) {
            throw new BaseException("库区id不能为空");
        }

    }
}
